package com.zh.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.common.ErrorCode;
import com.zh.domain.dto.milestone.AddMileStoneRequest;
import com.zh.domain.dto.milestone.UpdateMileStoneRequest;
import com.zh.domain.entity.*;
import com.zh.domain.vo.iteration.IterationVo;
import com.zh.domain.vo.milestone.MileStoneVo;
import com.zh.domain.vo.task.TaskCountVo;
import com.zh.domain.vo.task.TaskVo;
import com.zh.domain.vo.user.UserVO;
import com.zh.exception.ThrowUtils;
import com.zh.job.TaskManager;
import com.zh.service.*;
import com.zh.mapper.MilestoneMapper;
import kotlin.jvm.internal.Lambda;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Administrator
 * @description 针对表【milestones(里程碑表)】的数据库操作Service实现
 * @createDate 2025-02-09 16:24:10
 */
@Service
@Slf4j
public class MilestoneServiceImpl extends ServiceImpl<MilestoneMapper, Milestone>
        implements MilestoneService {
    @Resource
    private MilestoneMapper milestoneMapper;
    @Resource
    private UserService userService;
    @Resource
    @Lazy
    private ProjectService projectService;
    @Resource
    private ProjectUserService projectUserService;
    @Resource
    private ProjectDynamicsService projectDynamicsService;
    @Resource
    private MessageService messageService;
    @Resource
    private IterationService iterationService;
    @Resource
    private TaskService taskService;


    @Override
    @Transactional
    public Boolean add(AddMileStoneRequest addMileStoneRequest) {
        //1. 参数校验
        int loginId = StpUtil.getLoginIdAsInt();
        UserVO userVO = userService.getUserVoById(loginId);
        Integer proId = addMileStoneRequest.getProId();
        String title = addMileStoneRequest.getTitle();
        String description = addMileStoneRequest.getDescription();
        String remark = addMileStoneRequest.getRemark();
        LocalDateTime startTime = addMileStoneRequest.getStartTime();
        LocalDateTime endTime = addMileStoneRequest.getEndTime();
        ThrowUtils.throwIf(proId == null, ErrorCode.PARAMS_ERROR, "项目id不能为空");
        ThrowUtils.throwIf(title == null || title.length() > 100, ErrorCode.PARAMS_ERROR, "标题字数<100");
        // 2.校验时间 开始时间不能晚于开始时间.时间范围必须在项目范围内,多个里程碑时间不能重叠
        checkTime(startTime, endTime, proId);
        //3. 获取编号 插入milestone表
        LambdaQueryWrapper<Milestone> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(Milestone::getProId, proId)
                .eq(Milestone::getDeleted, 0);
        Long count = milestoneMapper.selectCount(queryWrapper1);
        String code = "M-" + "P" + proId + "-" + count.intValue() + 1;
        Milestone milestone = BeanUtil.copyProperties(addMileStoneRequest, Milestone.class);
        milestone.setProId(proId);
        milestone.setTitle(title);
        milestone.setDescription(description);
        milestone.setRemark(remark);
        milestone.setCode(code);
        milestone.setCreateBy(loginId);
        milestone.setUpdateBy(loginId);
        milestone.setCreateAt(LocalDateTime.now());
        milestone.setUpdateAt(LocalDateTime.now());
        // 初次创建状态为未开始
        milestone.setStatus(0);
        milestone.setDeleted(0);
        milestoneMapper.insert(milestone);
        //3.插入project_dynamics表
        TaskManager.execute(() -> {
            ProjectDynamics projectDynamics = new ProjectDynamics();
            projectDynamics.setProId(proId);
            projectDynamics.setContent(userVO.getName() + "创建了里程碑-" + title);
            projectDynamics.setCreateAt(LocalDateTime.now());
            projectDynamics.setCreateBy(loginId);
            projectDynamics.setUpdateAt(LocalDateTime.now());
            projectDynamics.setUpdateBy(loginId);
            projectDynamics.setStatus(1);
            projectDynamics.setDeleted(0);
            projectDynamicsService.save(projectDynamics);
        });
        //4.发送消息通知
        TaskManager.execute(() -> {
            Project project = projectService.getById(proId);
            Message message = new Message();
            message.setSendId(loginId);
            message.setNoticeType(0);
            message.setType(1);
            message.setParams(Map.of(
                    "proId", project.getId().toString(),
                    "payloadType", "project",
                    "title", project.getTitle()
            ));
            message.setContent(userVO.getName() + "为" + "项目 " + project.getTitle() + " 创建了里程碑-" + title);
            message.setStatus(1);
            message.setDeleted(0);
            message.setCreateAt(LocalDateTime.now());
            message.setUpdateAt(LocalDateTime.now());
            message.setCreateBy(loginId);
            message.setUpdateBy(loginId);
            LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ProjectUser::getProId, proId);
            List<ProjectUser> projectUserList = projectUserService.list(queryWrapper);
            List<Integer> userIdList = projectUserList.stream().map(ProjectUser::getUserId).collect(Collectors.toList());
            messageService.sendMessage(message, userIdList);
        });
        return true;
    }

    @Override
    @Transactional
    public Boolean updateMileStone(UpdateMileStoneRequest updateRequest) {
        int loginId = StpUtil.getLoginIdAsInt();
        return updateMileStone(loginId, updateRequest);
    }

    @Override
    @Transactional
    public Boolean updateMileStone(Integer userId, UpdateMileStoneRequest updateRequest) {
        MilestoneService proxy = (MilestoneService) AopContext.currentProxy();
        //1. 参数校验
        int loginId = userId;
        UserVO userVO = userService.getUserVoById(loginId);
        Integer id = updateRequest.getId();
        Integer proId = updateRequest.getProId();
        String title = updateRequest.getTitle();
        String description = updateRequest.getDescription();
        String remark = updateRequest.getRemark();
        LocalDateTime startTime = updateRequest.getStartTime();
        LocalDateTime endTime = updateRequest.getEndTime();
        Milestone milestone = proxy.getById(id);
        ThrowUtils.throwIf(milestone == null || !Objects.equals(milestone.getProId(), proId), ErrorCode.PARAMS_ERROR, "里程碑不存在");
        // 校验时间 开始时间不能晚于开始时间.时间范围必须在项目范围内,多个里程碑时间不能重叠
        checkTime(startTime, endTime, proId);
        synchronized (id.toString()) {
            //2.更新milestone表
            Milestone oldMilestone = proxy.getById(id);
            Milestone updateMileStone = new Milestone();
            BeanUtil.copyProperties(updateRequest, updateMileStone);
            LambdaUpdateWrapper<Milestone> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Milestone::getId, id)
                    .eq(Milestone::getProId, proId)
                    .set(null!=title,Milestone::getTitle, title)
                    .set(null!=description,Milestone::getDescription, description)
                    .set(null!=remark,Milestone::getRemark, remark)
                    .set(Milestone::getUpdateBy, loginId)
                    .set(null != startTime, Milestone::getStartTime, startTime)
                    .set(null != endTime, Milestone::getEndTime, endTime)
                    .set(Milestone::getUpdateAt, LocalDateTime.now())
                    .set(Milestone::getUpdateBy, loginId);
            boolean updated = proxy.update(updateWrapper);
            Milestone updatedMilestone = proxy.getById(id);
            //3.更新project_dynamics表
            TaskManager.execute(() -> {
                List<String> contentList = new ArrayList<>();
                if (StrUtil.isNotEmpty(title)) {
                    String content = userVO.getName() + "修改了里程碑" + oldMilestone.getTitle() + "的标题-" + oldMilestone.getTitle() + "->" + title;
                    contentList.add(content);
                }
                if (StrUtil.isNotEmpty(description)) {
                    String content = userVO.getName() + "修改了里程碑" + oldMilestone.getTitle() + "的描述";
                    contentList.add(content);
                }
                if (StrUtil.isNotEmpty(remark)) {
                    String content = userVO.getName() + "修改了里程碑" + oldMilestone.getTitle() + "的备注";
                    contentList.add(content);
                }
                if (startTime != null && endTime != null) {
                    String content = userVO.getName() + "修改了里程碑" + oldMilestone.getTitle() + "的开始时间-" + oldMilestone.getStartTime() + "->" + startTime + "结束时间-" + oldMilestone.getEndTime() + "->" + endTime;
                    contentList.add(content);
                }

                List<ProjectDynamics> projectDynamicsList = new ArrayList<>();
                contentList.forEach(content -> {
                    ProjectDynamics projectDynamics = new ProjectDynamics();
                    projectDynamics.setProId(proId);
                    projectDynamics.setContent(content);
                    projectDynamics.setContent(userVO.getName() + "修改了里程碑-" + title);
                    projectDynamics.setCreateAt(LocalDateTime.now());
                    projectDynamics.setCreateBy(loginId);
                    projectDynamics.setUpdateAt(LocalDateTime.now());
                    projectDynamics.setUpdateBy(loginId);
                    projectDynamics.setStatus(1);
                    projectDynamics.setDeleted(0);
                    projectDynamicsList.add(projectDynamics);
                });
                projectDynamicsService.saveBatch(projectDynamicsList);
            });
            //4.发送消息通知
            TaskManager.execute(() -> {
                Project project = projectService.getById(proId);
                Message message = new Message();
                message.setSendId(loginId);
                message.setNoticeType(0);
                message.setType(1);
                message.setParams(Map.of(
                        "proId", project.getId().toString(),
                        "payloadType", "project",
                        "title", project.getTitle()
                ));
                message.setContent(userVO.getName() + "更新了" + "项目" + project.getTitle() + " 里程碑-" + updatedMilestone.getTitle());
                message.setStatus(1);
                message.setDeleted(0);
                message.setCreateAt(LocalDateTime.now());
                message.setUpdateAt(LocalDateTime.now());
                message.setCreateBy(loginId);
                message.setUpdateBy(loginId);
                LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ProjectUser::getProId, proId);
                List<ProjectUser> projectUserList = projectUserService.list(queryWrapper);
                List<Integer> userIdList = projectUserList.stream().map(ProjectUser::getUserId).collect(Collectors.toList());
                messageService.sendMessage(message, userIdList);
            });
            return updated;
        }
    }

    @Override
    public List<MileStoneVo> listByProId(Integer proId) {
        if (proId == null) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<Milestone> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Milestone::getProId, proId)
                .eq(Milestone::getDeleted, 0)
                .orderByAsc(Milestone::getId)
                .orderByAsc(Milestone::getStartTime)
                .orderByAsc(Milestone::getEndTime)
                .orderByAsc(Milestone::getStatus)
                .orderByAsc(Milestone::getCreateAt)
                .orderByAsc(Milestone::getUpdateAt);
        List<Milestone> milestoneList = milestoneMapper.selectList(queryWrapper);
        //获取用户信息
        List<Integer> userIdList = milestoneList.stream()
                .flatMap(milestone -> Stream.of(milestone.getCreateBy(), milestone.getUpdateBy()))
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        Map<Integer, UserVO> userVOMap = userService.listUserVoByIds(userIdList).stream()
                .collect(Collectors.toMap(UserVO::getId, userVO -> userVO));
        //获取迭代列表、任务列表
        return milestoneList.stream().map(milestone -> {
            MileStoneVo mileStoneVo = BeanUtil.copyProperties(milestone, MileStoneVo.class);
            List<IterationVo> iterationVoList = iterationService.listByMilestoneId(milestone.getId());
            List<TaskVo> taskVoList = taskService.listByMileStoneIdDirectly(milestone.getId());
            mileStoneVo.setCreator(userVOMap.get(mileStoneVo.getCreateBy()));
            mileStoneVo.setUpdater(userVOMap.get(mileStoneVo.getUpdateBy()));
            mileStoneVo.setIterationVoList(iterationVoList);
            mileStoneVo.setTaskVoList(taskVoList);
            return mileStoneVo;
        }).collect(Collectors.toList());
    }

    @Override
    public MileStoneVo getMileStoneById(Integer id) {
        ThrowUtils.throwIf(null == id, ErrorCode.PARAMS_ERROR);
        Milestone milestone = milestoneMapper.selectById(id);
        if (milestone == null){
            return null;
        }
        MileStoneVo mileStoneVo = BeanUtil.copyProperties(milestone, MileStoneVo.class);
        //获取用户信息
        Integer createBy = mileStoneVo.getCreateBy();
        Integer updateBy = mileStoneVo.getUpdateBy();
        mileStoneVo.setCreator(userService.getUserVoById(createBy));
        mileStoneVo.setUpdater(userService.getUserVoById(updateBy));
        //获取迭代列表、任务列表
        mileStoneVo.setIterationVoList(iterationService.listByMilestoneId(id));
        mileStoneVo.setTaskVoList(taskService.listByMileStoneIdDirectly(id));
        return mileStoneVo;
    }

    @Override
    public void updateProcessById(Integer mileId) {
        List<TaskVo> taskVos = taskService.listByMileStoneId(mileId);
        if (CollectionUtil.isEmpty(taskVos)) {
            return;
        }
        long completeCount = taskVos.stream().filter(taskVo -> taskVo.getStatus() == 4).count();
        BigDecimal progress = new BigDecimal(completeCount).divide(new BigDecimal(taskVos.size()), 2, RoundingMode.HALF_UP);
        Milestone milestone = new Milestone();
        milestone.setId(mileId);
        milestone.setProgress(progress);
        if (progress.compareTo(BigDecimal.valueOf(1)) == 0) {
            milestone.setStatus(4);
            milestone.setCompleteTime(LocalDateTime.now());
        }
        milestone.setUpdateAt(LocalDateTime.now());
        milestoneMapper.updateById(milestone);
        log.info("更新里程碑-{}-进度-{}", mileId, progress);
    }

    @Override
    public TaskCountVo getTaskCount(Integer mileId) {
        List<TaskVo> taskVoList = taskService.listByMileStoneId(mileId);
        TaskCountVo taskCountVo = new TaskCountVo();
        taskCountVo.setMileId(mileId);

        int totalTask = 0;
        int doneTask = 0;
        int doingTask = 0;
        int undoTask = 0;
        int unStartTask = 0;
        int overdueTask = 0;
        int todayTask = 0;
        double process = 0.0;
        double overDueRate = 0.0;
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        for (TaskVo taskVo : taskVoList) {
            totalTask++;
            int status = taskVo.getStatus();
            switch (status) {
                case 0: // 规划中
                    unStartTask++;
                    break;
                case 1: // 进行中
                    doingTask++;
                    break;
                case 3: // 已逾期
                    overdueTask++;
                    break;
                case 4: // 已完成
                    doneTask++;
                    break;
//                case 5: // 已废弃
//                    undoTask++;
//                    break;
                default:
                    undoTask++;
                    break;
            }

            // 判断今日到期任务
            if (taskVo.getEndTime() != null && taskVo.getEndTime().format(formatter).equals(now.format(formatter))) {
                todayTask++;
            }
        }
        // 计算完成进度和逾期率
        if (totalTask > 0) {
            process = (double) doneTask / totalTask;
            overDueRate = (double) overdueTask / totalTask;
        }
        taskCountVo.setTotalTask(totalTask);
        taskCountVo.setDoneTask(doneTask);
        taskCountVo.setDoingTask(doingTask);
        taskCountVo.setUndoTask(undoTask);
        taskCountVo.setUnStartTask(unStartTask);
        taskCountVo.setOverdueTask(overdueTask);
        taskCountVo.setTodayTask(todayTask);
        taskCountVo.setProcess(process);
        taskCountVo.setOverDueRate(overDueRate);
        return taskCountVo;
    }

    private boolean checkTime(LocalDateTime startTime, LocalDateTime endTime, Integer proId) {
        if (startTime == null || endTime == null) {
            return true;
        }
        Project relatedProject = projectService.getById(proId);
        ThrowUtils.throwIf(startTime.isAfter(endTime), ErrorCode.PARAMS_ERROR, "开始时间不能晚于结束时间");
        ThrowUtils.throwIf(startTime.isBefore(relatedProject.getStartTime()) || endTime.isAfter(relatedProject.getEndTime()), ErrorCode.PARAMS_ERROR, "时间范围必须在项目范围内");
        ThrowUtils.throwIf(
                milestoneMapper.selectCount(new LambdaQueryWrapper<Milestone>()
                        .eq(Milestone::getProId, proId)
                        .and(i -> i
                                .or(wrapper -> wrapper.ge(Milestone::getStartTime, startTime).le(Milestone::getStartTime, endTime)) // 新里程碑的开始时间在现有范围内
                                .or(wrapper -> wrapper.ge(Milestone::getEndTime, startTime).le(Milestone::getEndTime, endTime))   // 新里程碑的结束时间在现有范围内
                                .or(wrapper -> wrapper.le(Milestone::getStartTime, startTime).ge(Milestone::getEndTime, endTime)) // 新里程碑完全包含现有里程碑
                        )) > 0,
                ErrorCode.PARAMS_ERROR, "时间范围不能重叠"
        );
        return true;
    }
}




